什麼是 scope ,為什麼好用?in Rails & why is it useful?
Scopes 都是定義在 rails models 裡面客制的詢問。每個 scope 接受兩個參數:
一個名稱,用來呼叫這個 scope
一個 lambda,用來完成這個詢問,像這樣:
class Fruit < ApplicationRecord
scope :with_juice, -> { where("juice > 0") }
end
如同呼叫一個 scope 的結果,會得到一個 ActiveRecord::Relation 物件。另外一個意思是說可以串接&結合 scopes!
例如:
Fruit.with_juice.with_round_shape.first(3)
先看個範例
def index
@books = Book.where("LENGTH(title) > 20")
end
這是一個 index controller action ,用來顯示超過20個字母的書名。如果想要其他地方使用這個詢問,就必須重複這段程式碼。重複的程式碼讓整個專案難以維護,那就把這個詢問移到一個 scope。像這樣:
class Book
scope :with_long_title, -> { where("LENGTH(title) > 20") }
end
現在 controller action 看起來像這樣:
def index
@books = Book.with_long_title
end
當想要把變數放到 scope ,在使用上有更多彈性。像這樣:
class Book
scope :with_long_title, ->(length) { where("LENGTH(title) > ?", length) }
end
這個 “?” 符號是一個 placeholder,會被後面的“length”值替換掉,讓程式碼更安全。如果要設定一個預設值:
class Book
scope :with_long_title, ->(length = 20) { where("LENGTH(title) > ?", length) }
end
Scopes 沒有做任何很厲害的事。就只是一個方法。其實也可以用類別方法做一樣的事情,像是:
class Fruit
def self.with_juice
where("juice > 0")
end
end
但是在這使用 scopes 而不使用類別方法有設計的優點。這是因為:
在功能性來說,唯一的差別是 scopes 保證一個 ActiveRecord::Relation ,但是類別方法不是。這樣當 scope 沒有回傳任何東西可以避免許多錯誤。
一個預設的 scope 會自動在 model 裡運作
class Post
default_scope { where(published: true) }
end
預設 scopes 很迷人,但是通常會因為忘記有定義過導致有不如預期的結果,跳出奇怪的錯誤,浪費時間 debugger。